/*************************************************
 * ThinkJot V2
 * Author: Jeswin P. (jeswin@process64.com)
 * Website: http://www.process64.com/thinkjot/
 * This code is distributed under the terms of the
 * Apache License, Version 2.0.
 * **********************************************/
using System;
using System.Web;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.Collections.Generic;
using System.Web.Security;

using CookComputing.XmlRpc;

using BlogsCore = ThinkJot.Core.Blogs;
using ThinkJot.Core.Configuration;
using ThinkJot.Core.Utils;
using Blogger = ThinkJot.Core.Blogs.Services.Blogger;
using MetaWeblog = ThinkJot.Core.Blogs.Services.MetaWeblog;
using MT = ThinkJot.Core.Blogs.Services.MovableType;

/// <summary>
/// -------- The metaweblog Catch -------
/// There is a catch in the MetaWeblog API.
/// The methods metaweblog_editPost, metaweblog_getPost do not expect a blogid.
/// Instead we will have to rely on postid, which the system generated automatically, and is a Guid.
/// However, this can leave a hole big enough in a multi-blog environment, where users cannot be
/// trusted across blogs.
/// So we do a work-around, we will identify the blog based on the username. 
/// And therein lies the catch; if you want to use the MetaWeblog API the administrator of the
/// blog cannot be the admin of any other blog. An OK workaround would be to create 
/// two seperate users for the same. 
/// 
/// You could alternatively give a different metaweblog endpoint for each blog. This can be tried
/// later. But I guess for now, making a distinct user is not too much.
/// </summary>


namespace ThinkJot.Core.Blogs.Services
{
    [XmlRpcService(
        Name = "MetaWeblogAPI",
       Description = "Implementation of MetaWeblogAPI for Thinkjot V2.")]
    public class MetaWeblogAPI : XmlRpcService, MetaWeblog.IMetaWeblogAPI, Blogger.IBloggerAPI, MT.IMovableTypeAPI
    {
        ////See 'The metaweblog Catch (^up^)'.         
  
        #region IMetaWeblogAPI Members

        public bool metaweblog_editPost(string postid, string username, string password, ThinkJot.Core.Blogs.Services.MetaWeblog.Post post, bool publish)
        {
            //We are gonna identify the blog from the username! <limitation of  TJ design w.r.t. metaweblog>
            BlogConfig blogConfig = ValidateAndGetBlogConfigForUser(username, password);

            ThinkJot.Core.Blogs.BlogEntry entry = new ThinkJot.Core.Blogs.BlogEntry();
            entry.UniqueId = new Guid(postid);
            entry.Title = post.title;
            
            if (post.dateCreated != DateTime.MinValue)
                entry.Time = post.dateCreated;
            //else don't change the time.

            entry.CategoryIds = BlogsCore.Category.GetCategoryIds(post.categories, blogConfig.Name);
            entry.Content = post.description;
            entry.Author = username;            
            entry.Publish = publish;
            entry.Syndicate = publish;  //if we publish, we also syndicate. 
            entry.AllowComments = publish; //if we publish, and allow comments
            entry.Update(blogConfig.Name);

            return true;    //we _probably_ made it. :) 
        }

        public MetaWeblog.CategoryInfo[] metaweblog_getCategories(string blogid, string username, string password)
        {
            //We are getting the blogid, but lets ignore that for consistency
            BlogConfig blogConfig = ValidateAndGetBlogConfigForUser(username, password);

            PathUtility pathUtil = new PathUtility();
            List<ThinkJot.Core.Blogs.Category> cats = ThinkJot.Core.Blogs.Category.GetAllCategories(blogConfig.Name);
            List<MetaWeblog.CategoryInfo> metaCats = new List<MetaWeblog.CategoryInfo>();
            foreach (ThinkJot.Core.Blogs.Category cat in cats)
            {
                MetaWeblog.CategoryInfo metaCatInfo = new MetaWeblog.CategoryInfo();
                metaCatInfo.categoryid = cat.Id.ToString();
                metaCatInfo.description = cat.Description;
                metaCatInfo.title = cat.Name;
                metaCatInfo.htmlUrl = pathUtil.GetBlogUrl(blogConfig.Name);
                metaCatInfo.rssUrl = pathUtil.CombineUrls(blogConfig.Name, "rss.xml");
                metaCats.Add(metaCatInfo);
            }
            return metaCats.ToArray();
        }

        public ThinkJot.Core.Blogs.Services.MetaWeblog.Post metaweblog_getPost(string postid, string username, string password)
        {
            BlogConfig blogConfig = ValidateAndGetBlogConfigForUser(username, password);

            MetaWeblog.Post post = new MetaWeblog.Post();
            ThinkJot.Core.Blogs.BlogEntry entry = ThinkJot.Core.Blogs.BlogEntry.GetBlogEntry(new Guid(postid), blogConfig.Name);
            post.description = entry.Content;
            post.postid = entry.UniqueId.ToString();
            post.dateCreated = entry.Time;
            post.permalink = BlogEntry.GetPermaLink(entry.UniqueId, blogConfig.Name);
            post.categories = ThinkJot.Core.Blogs.Category.GetCategoryStringsForIds(entry.CategoryIds, blogConfig.Name).ToArray();
            post.title = entry.Title;
            return post;
        }

        public ThinkJot.Core.Blogs.Services.MetaWeblog.Post[] metaweblog_getRecentPosts(string blogid, string username, string password, int numberOfPosts)
        {
            BlogConfig blogConfig = ValidateAndGetBlogConfigForUser(username, password);

            List<MetaWeblog.Post> posts = new List<MetaWeblog.Post>();
            List<ThinkJot.Core.Blogs.BlogEntry> entries = ThinkJot.Core.Blogs.BlogEntry.GetLastNormalTypeEntries(numberOfPosts, true, blogConfig.Name);
            foreach (ThinkJot.Core.Blogs.BlogEntry entry in entries)
            {
                MetaWeblog.Post post = new MetaWeblog.Post();
                post.description = entry.Content;
                post.postid = entry.UniqueId.ToString();
                post.dateCreated = entry.Time;
                post.categories = ThinkJot.Core.Blogs.Category.GetCategoryStringsForIds(entry.CategoryIds, blogConfig.Name).ToArray();
                post.title = entry.Title;
                posts.Add(post);
            }
            return posts.ToArray();
        }

        public string metaweblog_newPost(string blogid, string username, string password, ThinkJot.Core.Blogs.Services.MetaWeblog.Post post, bool publish)
        {
            BlogConfig blogConfig = ValidateAndGetBlogConfigForUser(username, password);

            ThinkJot.Core.Blogs.BlogEntry entry = new ThinkJot.Core.Blogs.BlogEntry();
            entry.Title = post.title;
            entry.Time = DateTime.Now.ToUniversalTime();
            entry.Author = username;
            entry.CategoryIds = BlogsCore.Category.GetCategoryIds(post.categories, blogConfig.Name);
            entry.Content = post.description;
            entry.Publish = publish;
            entry.Syndicate = publish;
            entry.AllowComments = publish;
            entry.Save(blogConfig.Name);
            
            return entry.UniqueId.ToString();
        }

        public MetaWeblog.MediaObjectUrl metaweblog_newMediaObject(string blogid, string username, string password, MetaWeblog.MediaObject media)
        {
            BlogConfig blogConfig = ValidateAndGetBlogConfigForUser(username, password);

            string fileName = Path.GetFileName(media.name);
            string savedFileName = ThinkJot.Core.Blogs.BlogEntry.SaveFile(fileName, media.bits, blogConfig.Name, false);
            MetaWeblog.MediaObjectUrl url = new MetaWeblog.MediaObjectUrl();
            url.url = new PathUtility().CombineUrls(new PathUtility().GetBlogMediaUrl(blogConfig.Name), savedFileName);
            return url;
        }

        public ThinkJot.Core.Blogs.Services.MetaWeblog.BlogInfo[] blogger_getUsersBlogs(string appKey, string username, string password)
        {
            BlogConfig blogConfig = ValidateAndGetBlogConfigForUser(username, password);

            MetaWeblog.BlogInfo blog = new MetaWeblog.BlogInfo();
            blog.blogid = blogConfig.Name;
            blog.blogName = blogConfig.Name;
            blog.url = new PathUtility().GetMappedBlogUrl(blogConfig.Name);
            return new MetaWeblog.BlogInfo[] { blog };
        }

        #endregion

        #region IBloggerAPI Members

        public bool blogger_deletePost(string appKey, string postid, string username, string password, bool publish)
        {
            try
            {
                BlogConfig blogConfig = ValidateAndGetBlogConfigForUser(username, password);
                BlogEntry.DeleteEntry(new Guid(postid), blogConfig.Name);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool blogger_editPost(string appKey, string postid, string username, string password, string content, bool publish)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public ThinkJot.Core.Blogs.Services.Blogger.Category[] blogger_getCategories(string blogid, string username, string password)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public ThinkJot.Core.Blogs.Services.Blogger.Post blogger_getPost(string appKey, string postid, string username, string password)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public ThinkJot.Core.Blogs.Services.Blogger.Post[] blogger_getRecentPosts(string appKey, string blogid, string username, string password, int numberOfPosts)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public string blogger_getTemplate(string appKey, string blogid, string username, string password, string templateType)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public Blogger.UserInfo blogger_getUserInfo(string appKey, string username, string password)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        ThinkJot.Core.Blogs.Services.Blogger.BlogInfo[] Blogger.IBloggerAPI.blogger_getUsersBlogs(string appKey, string username, string password)
        {
            BlogConfig blogConfig = ValidateAndGetBlogConfigForUser(username, password);
            Blogger.BlogInfo blogInfo = new Blogger.BlogInfo();
            blogInfo.blogid = blogConfig.BlogId;
            blogInfo.blogName = blogConfig.Name;
            blogInfo.url = new PathUtility().GetMappedBlogUrl(blogConfig.Name);
            return new Blogger.BlogInfo[] { blogInfo };
        }

        public string blogger_newPost(string appKey, string blogid, string username, string password, string content, bool publish)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public bool blogger_setTemplate(string appKey, string blogid, string username, string password, string template, string templateType)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion

        #region IMovableTypeAPI Members

        public ThinkJot.Core.Blogs.Services.MovableType.Category[] mt_getCategoryList(string blogid, string username, string password)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public ThinkJot.Core.Blogs.Services.MovableType.Category[] mt_getPostCategories(string postid, string username, string password)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public MT.PostTitle[] mt_getRecentPostTitles(string blogid, string username, string password, int numberOfPosts)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public MT.TrackbackPing[] mt_getTrackbackPings(string postid)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public bool mt_publishPost(string postid, string username, string password)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public bool mt_setPostCategories(string postid, string username, string password, ThinkJot.Core.Blogs.Services.MovableType.Category[] categories)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public string[] mt_supportedMethods()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public MT.TextFilter[] mt_supportedTextFilters()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        private BlogConfig ValidateAndGetBlogConfigForUser(string userName, string password)
        {
            if (!System.Web.Security.Membership.ValidateUser(userName, password))
                throw new XmlRpcFaultException(0, "You have to be a valid user to do that.");

            SystemConfiguration config = SystemConfiguration.GetConfig();
            Dictionary<string, BlogConfig> blogConfigs = config.Blogs.GetAll();
            foreach (BlogConfig blogConfig in blogConfigs.Values)
            {
                //The admin needs to be unique to use Metaweblog API
                //See 'The metaweblog Catch'
                if (blogConfig.Administrator == userName)
                {
                    if (!blogConfig.EnableMetaWeblogAPI)
                    {
                        throw new XmlRpcFaultException(0, "The metaweblog API is not enabled for this blog.");
                    }
                    return blogConfig;
                }
            }
            throw new XmlRpcFaultException(0, "The user needs to be an administrator of the blog to use the metaweblog API.");
        }   

        #endregion
    }
}